﻿using System;
using System.Collections.Generic;
using System.Linq;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using Habanero.Base;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using NUnit.Framework;

namespace FireStarterModeller.Test.Logic
{
    [TestFixture]
    public class TestDMToEntityClassDefConverter
    {
        [TestFixtureSetUp]
        public void SetupFixture()
        {
            TestUtilsLogic.SetupFixture();
        }

        [SetUp]
        public void SetupTest()
        {
            TestUtilsLogic.SetupTest();
        }

        [Test]
        public void Test_RelationshipConversion_EntityWithTypeParameter()
        {
            //---------------Set up test pack-------------------

            DMClass dmClass = TestUtilsLogic.CreateClassWithOneGuidProperty();
            DMProperty @property = TestUtilsLogic.AddPropertyWithNoRules(dmClass);
            DMClass relatedClass = TestUtilsLogic.CreateClassWithOneGuidProperty(dmClass.Assembly);
            DMProperty relatedProperty = TestUtilsLogic.AddPropertyWithNoRules(relatedClass);
            DMRelationship dmRelationship = new DMRelationship();
            dmRelationship.RelatedClass = relatedClass;
            dmRelationship.RelationshipType = RelationshipType.Association;
            dmRelationship.Cardinality = Cardinality.Single;
            dmRelationship.RelationshipName = TestUtilsShared.GetRandomString();
            dmRelationship.ReverseRelationship.RelationshipName = TestUtilsShared.GetRandomString();
            dmRelationship.DeleteAction = DeleteParentAction.DoNothing;
            DMRelationshipProperty dmRelationshipProperty = new DMRelationshipProperty
            {
                OwnerProperty = @property,
                RelatedProperty = relatedProperty
            };
            dmRelationship.RelationshipProperties.Add(dmRelationshipProperty);
            dmClass.OwnerRelationships.Add(dmRelationship);

            //---------------Execute Test ----------------------
            ClassDefCol classDefs = new DMToEntityClassDefsConverter().Convert((DMSolution) dmClass.Solution);
            IClassDef classDef = classDefs["FireStarterModeller.BO", "ENTITY_" + dmClass.ClassNameBO.ToUpper()];
            IRelationshipDef relationshipDef = classDef.RelationshipDefCol[dmRelationship.RelationshipName];

            //---------------Test Result -----------------------
            Assert.AreEqual(typeof(Entity).Name, relationshipDef.RelatedObjectClassName);
            Assert.AreEqual(relatedClass.ClassNameBO, relationshipDef.RelatedObjectTypeParameter);
        }
    
        [Test]
        public void Test_TwoClassesConversion_UsingEntity()
        {
            //---------------Set up test pack-------------------
            DMClass dmClass = TestUtilsLogic.CreateClassWithOneGuidProperty();
            DMClass dmClass2 = TestUtilsLogic.CreateClassWithOneGuidProperty(dmClass.Assembly);

            //---------------Execute Test ----------------------
            ClassDefCol classDefs = new DMToEntityClassDefsConverter().Convert((DMSolution) dmClass.Solution);
            IClassDef classDef1 = classDefs["FireStarterModeller.BO", typeof(Entity).Name + "_" + dmClass.ClassNameBO];
            IClassDef classDef2 = classDefs["FireStarterModeller.BO", typeof(Entity).Name + "_" + dmClass2.ClassNameBO];

            //---------------Test Result -----------------------
            Assert.AreEqual(2, classDefs.Count);
            Assert.AreEqual(classDef1.ClassNameExcludingTypeParameter, classDef2.ClassNameExcludingTypeParameter);
            StringAssert.StartsWith(typeof(Entity).Name, classDef1.ClassName);

            Assert.AreEqual(dmClass.ClassNameBO, classDef1.TypeParameter);
            Assert.AreEqual(dmClass2.ClassNameBO, classDef2.TypeParameter);
        }

        [Test]
        public void Test_EntityClassConversion_AdaptedForEntity()
        {
            //---------------Set up test pack-------------------
            DMClass dmClass = TestUtilsLogic.CreateClassWithOneGuidProperty();
            DMProperty property1 = TestUtilsLogic.AddPropertyWithNoRules(dmClass);
            DMProperty property2 = TestUtilsLogic.AddPropertyWithNoRules(dmClass);
            Entity entity = new Entity();
            //---------------Execute Test ----------------------
            ClassDefCol classDefs = new DMToEntityClassDefsConverter().Convert((DMSolution) dmClass.Solution);
            IClassDef classDef1 = classDefs["FireStarterModeller.BO", typeof(Entity).Name + "_" + dmClass.ClassNameBO];
            //---------------Test Result -----------------------
            Assert.AreEqual(3 + entity.Props.Count, classDef1.PropDefcol.Count);
            foreach (IBOProp prop in entity.Props)
                Assert.IsTrue(classDef1.PropDefcol.Contains(prop.PropertyName));
            Assert.IsTrue(classDef1.PropDefcol.Contains(property1.PropertyName));
            Assert.IsTrue(classDef1.PropDefcol.Contains(property2.PropertyName));
            Assert.AreEqual(entity.ClassDef.PrimaryKeyDef.Count, classDef1.PrimaryKeyDef.Count);
            Assert.AreEqual(entity.ClassDef.PrimaryKeyDef[0].PropertyName, classDef1.PrimaryKeyDef[0].PropertyName);
        }

        [Test]
        public void Test_ConvertToEntityClassDefs_WhenPrimaryKeyNotIsObjectID_ShouldReplaceWithEntityIDAndSetAsObjectID
            ()
        {
            //---------------Set up test pack-------------------
            DMClass dmClass = TestUtilsLogic.CreateClassWithStringPropertyAsPK();
            TestUtilsLogic.AddPropertyWithNoRules(dmClass);
            TestUtilsLogic.AddPropertyWithNoRules(dmClass);

            dmClass.Assembly.Solution.Save();

            Entity entity = new Entity();
            //---------------Assert Preconditions---------------
            Assert.IsFalse(dmClass.ObjectIdentity.IsObjectID.Value);
            Assert.AreEqual("System.String", dmClass.ObjectIdentity.Properties[0].PropertyTypeString);
            //---------------Execute Test ----------------------
            ClassDefCol classDefs = new DMToEntityClassDefsConverter().Convert((DMSolution) dmClass.Solution);
            IClassDef classDef1 = classDefs["FireStarterModeller.BO", typeof(Entity).Name + "_" + dmClass.ClassNameBO];
            //---------------Test Result -----------------------
            Assert.AreEqual
                (dmClass.Properties.Count + entity.Props.Count, classDef1.PropDefcol.Count,
                 "The new ClassDef should have the three properties from the DMClass plus "
                 + "the two standard Props from the Entity (EntityID, DMClassID)");
            foreach (IBOProp prop in entity.Props)
            {
                Assert.IsTrue(classDef1.PropDefcol.Contains(prop.PropertyName));
            }
            foreach (DMProperty dmProp in dmClass.Properties)
            {
                Assert.IsTrue(classDef1.PropDefcol.Contains(dmProp.PropertyName));
            }

            Assert.AreEqual
                (entity.ClassDef.PrimaryKeyDef.Count, classDef1.PrimaryKeyDef.Count,
                 "The Primary Key defined for the DMClass has been replaced with the Primary from the Entity (i.e. The EntityID)");
            Assert.AreEqual(entity.ClassDef.PrimaryKeyDef[0].PropertyName, classDef1.PrimaryKeyDef[0].PropertyName);
            Assert.IsTrue(classDef1.PrimaryKeyDef.IsGuidObjectID);
        }

[Ignore("Peter working on this")]
        [Test]
        public void Test_ConvertToEntityClassDefs_ShouldCreateUniqueKey_WithTheSamePropsAsThePrimaryKeyForTheDMClass()
        {
            //---------------Set up test pack-------------------
            DMClass dmClass = TestUtilsLogic.CreateClassWithStringPropertyAsPK();
            TestUtilsLogic.AddPropertyWithNoRules(dmClass);
            TestUtilsLogic.AddPropertyWithNoRules(dmClass);
            dmClass.Assembly.Solution.Save();
            DMProperty primaryKeyProp = dmClass.ObjectIdentity.Properties[0];
            Entity entity = new Entity();
            //---------------Assert Preconditions---------------
            Assert.IsFalse(dmClass.ObjectIdentity.IsObjectID.Value);
            Assert.AreEqual("System.String", dmClass.ObjectIdentity.Properties[0].PropertyTypeString);
            //---------------Execute Test ----------------------
            ClassDefCol classDefs = new DMToEntityClassDefsConverter().Convert((DMSolution) dmClass.Solution);
            IClassDef classDef1 = classDefs["FireStarterModeller.BO", typeof(Entity).Name + "_" + dmClass.ClassNameBO];
            //---------------Test Result -----------------------
            Assert.AreEqual
                (dmClass.Properties.Count + entity.Props.Count, classDef1.PropDefcol.Count,
                 "The new ClassDef should have the three properties from the DMClass plus "
                 + "the two standard Props from the Entity (EntityID, DMClassID)");
            foreach (IBOProp prop in entity.Props)
            {
                Assert.IsTrue(classDef1.PropDefcol.Contains(prop.PropertyName));
            }
            foreach (DMProperty dmProp in dmClass.Properties)
            {
                Assert.IsTrue(classDef1.PropDefcol.Contains(dmProp.PropertyName));
            }

            Assert.AreEqual
                (entity.ClassDef.PrimaryKeyDef.Count, classDef1.PrimaryKeyDef.Count,
                 "The Primary Key defined for the DMClass has been replaced with the Primary from the Entity (i.e. The EntityID)");
            Assert.AreEqual(entity.ClassDef.PrimaryKeyDef[0].PropertyName, classDef1.PrimaryKeyDef[0].PropertyName);
            Assert.IsTrue(classDef1.PrimaryKeyDef.IsGuidObjectID);

            Assert.AreEqual(1, classDef1.KeysCol.Count);
            string keyName = "DomainPrimaryKey_" + primaryKeyProp.PropertyName;
            Assert.IsNotNull(classDef1.KeysCol[keyName]);
            KeyDef keyDef = (KeyDef) classDef1.KeysCol[keyName];
            Assert.AreEqual(dmClass.ObjectIdentity.Properties.Count, keyDef.Count);
            //foreach (DMProperty dmProperty in dmClass.ObjectIdentity.Properties)
            //{

            //    Assert.IsTrue(keyDef...Contains(dmProperty.PropertyName));
            //}
        }


    }
}